package com.tools.web.interceptor.auth;

import com.tools.common.object.Force;
import com.tools.common.object.json.JsonKit;
import com.tools.common.object.Note;
import com.tools.common.thread.Timeunit;
import com.tools.db.cache.local.LocalCache;
import com.tools.web.interceptor.access.AccessManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;

/**
 * 用于 “用户只允许单端在线的用户认证” 的管理器
 * */
@Note("用于 “用户只允许单端在线的用户认证” 的管理器")
public final class SingleLocalAuthenticationManager extends GenericAuthenticationManager {

    @Note("本地缓存实例")
    private final LocalCache localCache;

    @Note("日志对象")
    private static final Logger LOGGER = LoggerFactory.getLogger(SingleLocalAuthenticationManager.class);

    /* **************************************************************************************
     *
     *          构造器
     *
     * **************************************************************************************
     * */

    public SingleLocalAuthenticationManager(LocalCache localCache, AuthSource source,
                                            AuthUserService authUserService) {
        this(localCache, source, authUserService, null);
    }

    public SingleLocalAuthenticationManager(LocalCache localCache, AuthSource source,
                                            AuthUserService authUserService, AccessManager accessManager) {
        super(source, authUserService, accessManager);
        this.localCache = Objects.requireNonNull(localCache);
    }

    /* **************************************************************************************
     *
     *          功能方法
     *
     * **************************************************************************************
     * */

    @Note("从缓存中获取 SingleAuthUser 对象")
    protected Res getAuthUser(String key, AuthToken token) {
        String json = (String) this.localCache.get(key);
        if(json == null) {
            return super.protected_getResIfExpired(token);
        }
        SingleAuthUser authUser = JsonKit.toEntity(json, SingleAuthUser.class);;
        String srcUuid = authUser.getUuid();
        String srcDeviceTypeId = authUser.getDeviceTypeId();
        if(Objects.equals(srcUuid, token.getUuid()) &&
                Objects.equals(srcDeviceTypeId, token.getDeviceTypeId())) {
            return new Res(true, authUser);
        }
        return new Res(false, null);
    }


    @Note("将 SingleAuthUser 对象放入缓存中，并设置过期时间")
    protected void setAuthUser(String key, AuthUser srcAuthUser, AuthToken token) {
        SingleAuthUser authUser = (SingleAuthUser) srcAuthUser;
        authUser.setUuid(token.getUuid());
        authUser.setDeviceTypeId(token.getDeviceTypeId());
        authUser.setUserType(token.getUserType());
        String json = JsonKit.toJSON(authUser);
        this.localCache.put(key, json, token.getExpiration());
    }


    @Note("将指定的用户过期")
    protected void removeAuthUser(String key) {
        this.localCache.remove(key);
    }


    @Note("更新用户数据对象")
    protected void updateAuthUser(String key, AuthUser authUser, String separator) {
        Force<Object> force = new Force<Object>(authUser) {
            @Override
            public Object force(Object source) {
                String s = (String) source;
                if(s == null) return null;
                SingleAuthUser oldAuthUser = JsonKit.toEntity(s, SingleAuthUser.class);
                SingleAuthUser newAuthUser = getParam(0, SingleAuthUser.class);
                newAuthUser.copyBaseUserDataTo(oldAuthUser);
                newAuthUser.copyCustomDataMapTo(oldAuthUser);
                return JsonKit.toJSON(oldAuthUser);
            }
        };
        this.localCache.modify(key, force);
    }


    @Override
    protected Logger protected_getLogger() {
        return LOGGER;
    }

    @Override
    protected Timeunit protected_getTimeunitToBeUsed() {
        return Timeunit.MILL;
    }

    @Override
    protected void protected_loginOut(String key, String deviceTypeId, String uuid,
                                      AuthUser authUser, String separator) {
        this.removeAuthUser(key);
    }
}
